#pragma once
#include <QStandardItemModel>
#include <QListView>
#include "QShapeVersion.h"
#include "ShapeOperation.h"
#include <QPointer>
#include "Render/QIVtkSelectionPipeline.h"
#include <QTimer>

class FeatureShape;
class MainWindow;
class ExpressionManager;

// 整个历史流内部采用智能指针管理内存问题
// Version不会被GC，所以不需要智能指针管理其内存
// 整个历史流版本需保证任何回溯操作不得改变version actor的数量

class HistoryManager : public QObject
{
	Q_OBJECT

public:
	HistoryManager(QStandardItemModel* listModel, QListView* listView, MainWindow* mainWindow);

	// 一定要在actor完成cache之后调用
	// 应用OP, 会触发Version更新
	void applyOperation(ShapeOperation* op);

	// 通过键盘快捷键或工具栏 <-> 触发，一次只会回退或前进一步，理论上FeatureShape不会发生变化
	bool undo(bool bRemoveHistoryItem = true);
	bool redo(bool bAddHistoryItem = true);

	// 修改指定version，这个version的operation应该已经发生了变化
	void ModifyVersion(uint versionID);

	void OnOperationCancel();

	ExpressionManager* GetExpressionManager()
	{
		return m_expressionManager;
	}

	QList<QPointer<QShapeVersion>> GetHistoryVersion()
	{
		return historyVersion;
	}

	// 保存operation到文件中
	void saveOperations();
	// 从文件中加载operation
	void loadOperations(const std::string& filename);

	bool IsModify() const
	{
		return bIsModify;
	}

	void OnLeftButtonDown();
	void onItemChanged(QStandardItem* item);
	// 编辑Actor
	void EditActor(Handle(QIVtkSelectionPipeline) actor);
private:
	// 重新创建需要保证: 1.初始化feature value 2.初始化feature shape 3.初始化position 4.删除旧的actor
	bool redoCreateShape(CreateShapeOperation* op);
	bool redoBooleanShape(BooleanOperation* op);
	bool redoDeleteShape(DeleteShapeOperation* op);
	bool redoHollowShape(HollowOperation* op);
	bool redoTransformShape(TransformOperation* op);
	bool redoStretchShape(StretchOperation* op);
	bool redoRevolveShape(RevolveOperation* op);
	bool redoRoundOffShape(RoundOffOperation* op);
	bool redoSketch(SketchOperation* op);
	bool redoFillFace(FillFaceOperation* op);
	bool redoCreateFromObject(CreateShapeFromObjectOperatopn* op);
	bool redoDetachEdge(DetachEdgeOperation* op);
	bool redoDetachFace(DetachFaceOperation* op);
	bool redoUncoverFace(UncoverFaceOperation* op);
	bool redoCoverFace(CoverFaceOperation* op);
	bool redoMoveEdge(MoveEdgeOperation* op);
    bool redoMoveFace(MoveFaceOperation* op);
	bool redoSection(SectionOperation* op);

	// 在触发这个函数之间设置m_currentVersion的op
	void redoUpdateItemState();
	void undoUpdateItemState();

	void processSingleClick();

	// 当前是否为最新版本
	bool isLatestVersion() const
	{
		return m_itemIndex == m_listModel->rowCount() - 1;
	}

	// edit version并到最新版本
	void editVersion(QPointer<QShapeVersion> version);
	void editVersion(QPointer<QShapeVersion> version, int versionItemRow);

	// 得到version对应的item row
    int getItemRow(QPointer<QShapeVersion> version);

	// 得到version对应的feature shape
    std::shared_ptr<FeatureShape> getFeatureShape(QPointer<QShapeVersion> version, int versionItemRow);
    std::shared_ptr<FeatureShape> getFeatureShape(QPointer<QShapeVersion> version);

	// 从 actor 找到 version ------ 有点绕，设计缺陷
    QPointer<QShapeVersion> getVersion(Handle(QIVtkSelectionPipeline) actor, bool bIncludeFuture = false);

	// 保存mix shape
    void saveMixShape(const std::vector<std::shared_ptr<FeatureShape>>& shapes);

private:
	QStandardItemModel* m_listModel;
	QListView* m_listView;
	MainWindow* m_mainWindow;
	ExpressionManager* m_expressionManager;
	// 开始的时间戳，用于当作保存的文件名
	uint m_startTime;
	// 暂时的actor不会加入cache，只用于展示
	Handle(QIVtkSelectionPipeline) tempActor;

	bool bIsRedo = false;
	// 连续 redo 的 target index
	int RedoTargetIndex = -1;
	bool bIsDirty = false;
	bool bIsModify = false;
	// 是否希望不触发itemChanged event
	bool bNotOccurItemChangeEvent = false;

	// 点击checkbox会触发item clieck, 阻止它
	bool bItemChangedEventOccurred = false;
	// 记录当前item的index
	int m_itemIndex = -1;
	// 避免双击导致单击
	QTimer* clickTimer;
	// 待处理的index
	QModelIndex pendingIndex;

	// 现阶段所有的FeatureShape
	std::vector<std::shared_ptr<FeatureShape>> m_currentFeatureShapes;

	// 现在的version
    QPointer<QShapeVersion> m_currentVersion;
	// 历史版本
	QList<QPointer<QShapeVersion>> historyVersion;
	// 未来版本
	QList<QPointer<QShapeVersion>> futureVersion;

public slots:
	void onItemDoubleClicked(const QModelIndex& index);
	void onItemClicked(const QModelIndex& index);
};

